﻿using Common.Device.Enums;
using Common.Device.Interfaces;
using Common.Device.Models;
using Common.Device.Views;
using Common.Tool;
using Common.Tool.FileTools;
using Common.Tool.Models;
using Common.View.Base;
using HandyControl.Tools.Extension;
using Newtonsoft.Json.Linq;
using NPOI.SS.Formula.Functions;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using NPOI.XWPF.UserModel;
using Org.BouncyCastle.Asn1.X509;
using Prism.Commands;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Runtime.Remoting.Metadata.W3cXsd2001;
using System.Security.Policy;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Xml.Linq;

namespace Common.Device.ViewModels
{
    public class TestListViewModel : BindableBase
    {
        CancellationTokenSource cancellationToken = null;//停止
        ManualResetEvent manualReset = null;//暂停、继续
        private Enums.TestEnum.StartState startState = TestEnum.StartState.开始;
        /// <summary>
        /// 通道编号
        /// </summary>
        public string num { get; set; }
        private bool loadOk = true;
        /// <summary>
        /// 加载表格状态
        /// </summary>
        public bool LoadOk
        {
            get { return loadOk; }
            set { SetProperty(ref loadOk, value); }
        }
        /// <summary>
        /// 开始状态 枚举
        /// </summary>
        public Enums.TestEnum.StartState StartState
        {
            get { return startState; }
            set { SetProperty(ref startState, value); }
        }
        private Enums.TestEnum.TestState state = TestEnum.TestState.等待;
        /// <summary>
        /// 当前测试状态
        /// </summary>
        public Enums.TestEnum.TestState State
        {
            get { return state; }
            set { SetProperty(ref state, value); }
        }
        bool? isAllCheck = null;
        /// <summary>
        /// 是否全选
        /// </summary>
        public bool? IsAllCheck
        {
            get { return isAllCheck; }
            set
            {
                if (StartState == TestEnum.StartState.停止) { return; }
                SetProperty(ref isAllCheck, value);
                if (isAllCheck != null)
                {
                    foreach (var item in orders)
                    {
                        item.IsCheck = isAllCheck.Value;
                    }
                }
            }
        }
        string code = "产品编码";
        /// <summary>
        /// 产品编码
        /// </summary>
        public string Code
        {
            get { return code; }
            set { SetProperty(ref code, value); }
        }
        double time = 0.0;
        /// <summary>
        /// 测试时间
        /// </summary>
        public double Time
        {
            get { return time; }
            set { SetProperty(ref time, value); }
        }
        double percent = 0.0;
        /// <summary>
        /// 测试进度
        /// </summary>
        public double Percent
        {
            get { return percent; }
            set { SetProperty(ref percent, value); }
        }
        string testItem = "当前测试项";
        /// <summary>
        /// 当前测试项
        /// </summary>
        public string TestItem
        {
            get { return testItem; }
            set { SetProperty(ref testItem, value); }
        }
        private ObservableCollection<TestOrder> orders = new ObservableCollection<TestOrder>();
        /// <summary>
        /// 测试项集合
        /// </summary>
        public ObservableCollection<TestOrder> Orders
        {
            get { return orders; }
            set { SetProperty(ref orders, value); }
        }
        public ICommand DelCommand { get => new DelegateCommand<TestOrder>(Del); }
        /// <summary>
        /// 删除测试项
        /// </summary>
        /// <param name="order"></param>
        public void Del(TestOrder order)
        {
            //是否在测试中
            if (StartState == TestEnum.StartState.停止) { return; }
            var result = View.Controls.Dialogs.TipView.Show($"确认删除测试项[{order.index}] {order.name}?", new Dictionary<string, Brush> { { "删除", View.Base.Colors.PrimaryColor }, { "取消", View.Base.Colors.DangerColor } });
            if (result == "删除")
            {
                try
                {
                    //移除
                    orders.Remove(order);
                    //重新计算序号
                    for (int i = 0; i < orders.Count; i++)
                    {
                        orders[i].index = i + 1;
                    }
                    //刷新界面
                    Orders = new System.Collections.ObjectModel.ObservableCollection<TestOrder>(orders);
                }
                catch (Exception ex)
                {
                    HandyControl.Controls.MessageBox.Error("删除测试项失败" + ex.Message); return;
                }
            }
        }
        public ICommand DelALLCommand { get => new DelegateCommand(DelAll); }
        public void DelAll()
        {
            //是否在测试中
            if (StartState == TestEnum.StartState.停止) { return; }
            var result = View.Controls.Dialogs.TipView.Show($"确认删除所有测试项?", new Dictionary<string, Brush> { { "删除", View.Base.Colors.PrimaryColor }, { "取消", View.Base.Colors.DangerColor } });
            if (result == "删除")
            {
                try
                {
                    orders.Clear();
                    Orders = new System.Collections.ObjectModel.ObservableCollection<TestOrder>(orders);
                }
                catch (Exception ex)
                {
                    HandyControl.Controls.MessageBox.Error("删除测试项失败" + ex.Message); return;
                }
            }
        }
        public ICommand Test { get => new DelegateCommand(test); }
        /// <summary>
        /// 测试或停止测试
        /// </summary>
        public void test()
        {
            if (StartState == TestEnum.StartState.开始)
            {
                Start();  
            }
            else if (StartState == TestEnum.StartState.停止)
            {
                Stop();
            }
        }
        /// <summary>
        /// 初始化界面
        /// </summary>
        /// <param name="code">产品编码</param>
        public void Init(string code = "")
        {
            StartState = TestEnum.StartState.停止;
            State = TestEnum.TestState.等待;
            Code = code;
            Time = 0.0;
            Percent = 0.0;
            //清空日志
            document.Clear();
            foreach (var order in Orders)
            {
                order?.Init();
                //传递日志类
                order.document = document;
            }
        }
        /// <summary>
        /// 开始测试
        /// </summary>
        /// <param name="code">条码</param>
        /// <param name="cancellationToken">异步方法取消令牌</param>
        /// <param name="manualReset">异步方法暂停启动</param>
        /// <returns></returns>
        public async Task<bool> Start(string code1 = "", CancellationTokenSource cancellationToken = null, ManualResetEvent manualReset = null)
        {
            //实例化令牌和暂停启动
            this.cancellationToken = cancellationToken ?? new CancellationTokenSource();
            this.manualReset = manualReset ?? new ManualResetEvent(true);
            //测试项为空，则不执行测试
            if (Orders.Count(o => o.IsCheck) == 0)
            {
                loadOk = true;
                return false;
            }
            //加载中
            LoadOk = false;
            Init(code1);
            document.AppendTile1(num, "开始测试");
            State = TestEnum.TestState.测试;
            //计算测试指令的总数，用于进度条
            int all = orders.Sum(o => o.orders.Count);
            await Task.Run(() =>
            {
                //时间显示
                DispatcherTimer itemTestTimer = null;
                try
                {
                    //循环测试项测试
                    foreach (var order in Orders)
                    {
                        LoadOk = true;
                        if (order.IsCheck)
                        {
                            //时间显示
                            itemTestTimer = new DispatcherTimer(new TimeSpan(TimeSpan.TicksPerMillisecond * 5), DispatcherPriority.Normal, delegate
                            {
                                Time = orders.Sum(o => o.Time);
                                Percent = orders.Sum(o => o.orders.Count(o1 => o1.state == TestEnum.TestState.通过)) * 100.0 / all;
                            }, Application.Current.Dispatcher);
                            itemTestTimer.Start();
                            //刷新界面当前测试项
                            TestItem = order.name;
                            //传递测试项集合给当前测试项
                            order.TestOrders = orders;
                            //启动测试项测试
                            order.Start(this.cancellationToken.Token, this.manualReset);
                            itemTestTimer.Stop();
                            if (order.State != TestEnum.TestState.通过 && order.ngStop)
                            {
                                //失败停止
                                return;
                            }
                            if (order.name=="输入蓝牙")
                            {
                                code=order.orders[0].result.result;
                            }
                            //order.TestOrders.mes
                        }
                    }
                }
                catch (OperationCanceledException)
                {
                    document.AppendTile1(num, "停止测试");
                }
                catch (Exception ex)
                {
                    document.AppendTile1(num, ex.Message);
                }
                finally
                {
                    //测试完成
                    LoadOk = true;
                    itemTestTimer?.Stop();
                    cancellationToken?.Cancel();
                    //更新测试状态
                    State = Orders.Count(o => o.State != TestEnum.TestState.通过) == 0 ? TestEnum.TestState.通过 : TestEnum.TestState.失败;

                    if (orders.Last().name.Contains("结束测试")
                    && orders.Last().IsCheck
                    && orders.Last().State == TestEnum.TestState.等待
                    && State == TestEnum.TestState.失败)
                    {                    
                        //判断最后测试项为结束测试，则执行断电初始化逻辑
                        orders.Last().Start();
                    }
                    document.AppendTile1(num, "测试结束:" + State.ToString());
                    //刷新进度条
                    Percent = orders.Sum(o => o.orders.Count(o1 => o1.state == TestEnum.TestState.通过)) * 100.0 / all;
                    //保存日志
                    SaveLog();
                    DeviceService.IsStop = false;
                    StartState = TestEnum.StartState.开始;
                }
            });
            return State == TestEnum.TestState.通过;
        }
        /// <summary>
        /// 停止测试
        /// </summary>
        /// <returns></returns>
        public async Task Stop()
        {
            await Task.Run(() =>
            {
                DeviceService.IsStop = true;
                LoadOk = false;
                //取消关联令牌的异步方法
                cancellationToken?.Cancel();
                while (StartState == TestEnum.StartState.停止)
                {
                    Thread.Sleep(100);
                }
            });
            StartState = TestEnum.StartState.开始;
            State = TestEnum.TestState.等待;
            LoadOk = true;
            DeviceService.IsStop = false;
        }
        public void SaveLog()
        {
            try
            {
                string sn = code;
                if (string.IsNullOrEmpty(code))
                {
                    sn = "null";
                }
                //结果
                bool result = State == TestEnum.TestState.通过;
                //测试时间
                DateTime time = DateTime.Now;
                //创建文件
                CreateTestLogger(sn, result, time);
                //写日志到txt文件中
                foreach (var text in document.Text)
                {
                    log.Information(text);
                }
                //生成excel文件
                IWorkbook workbook = new XSSFWorkbook();
                ICellStyle cellStyle = workbook.CreateCellStyle();
                cellStyle.WrapText = true;
                cellStyle.VerticalAlignment = NPOI.SS.UserModel.VerticalAlignment.Center;
                ISheet sheet = workbook.CreateSheet("001");
                IRow row = sheet.CreateRow(0);
                row.CreateCell(0).SetCellValue("序号");
                row.CreateCell(1).SetCellValue("测试项");
                row.CreateCell(2).SetCellValue("设备标识");
                row.CreateCell(3).SetCellValue("类型");
                row.CreateCell(4).SetCellValue("参数");
                row.CreateCell(5).SetCellValue("测试次数");
                row.CreateCell(6).SetCellValue("范围");
                row.CreateCell(7).SetCellValue("结果");
                row.CreateCell(8).SetCellValue("时间");
                row.CreateCell(9).SetCellValue("测试数据");
                foreach (var order in orders)
                {
                    row = sheet.CreateRow(order.index);
                    NpoiHelper.WriteCell(row, 0, order.index, cellStyle);
                    NpoiHelper.WriteCell(row, 1, order.name, cellStyle);
                    List<string> names = new List<string>();
                    if (order.deviceNames.Contains(null))
                    {
                        foreach (var name in order.deviceNames)
                        {
                            names.Add(name == null ? "null" : name);
                        }
                    }
                    else
                    {
                        names = order.deviceNames;
                    }
                    NpoiHelper.WriteCell(row, 2, string.Join("\r\n", names), cellStyle);
                    NpoiHelper.WriteCell(row, 3, string.Join("\r\n", order.orderTemps), cellStyle);
                    NpoiHelper.WriteCell(row, 4, string.Join("\r\n", order.orderParameters), cellStyle);
                    NpoiHelper.WriteCell(row, 5, order.testTime);
                    NpoiHelper.WriteCell(row, 6, string.Join("\r\n", order.orderRanges), cellStyle);
                    NpoiHelper.WriteCell(row, 7, string.Join("\r\n", order.states), cellStyle);
                    NpoiHelper.WriteCell(row, 8, string.Join("\r\n", order.Times.Select(o=>o.ToString("F2"))), cellStyle);
                    NpoiHelper.WriteCell(row, 9, string.Join("\r\n", order.ResultList), cellStyle);
                    NpoiHelper.SetAutoWidth(sheet);
                }
                //保存测试excel文档
                string path = Environment.CurrentDirectory+$"/logs/testlog/{time.ToString("yyyyMMdd")}/{sn}_{(result ? "OK" : "NG")}_{time.ToString("HHmmssfff")}.xlsx";
                NpoiHelper.SaveExcel(workbook, path);
            }
            catch (Exception)
            {
            }
        }
    }

    /// <summary>
    /// 测试项
    /// </summary>
    public class TestOrder : BindableBase
    {
        public ObservableCollection<TestOrder> TestOrders=null;
        private bool isCheck;
        /// <summary>
        /// 是否选中
        /// </summary>
        public bool IsCheck
        {
            get { return isCheck; }
            set { SetProperty(ref isCheck, value); }
        }
        /// <summary>
        /// 测试项索引
        /// </summary>
        public int index { get; set; }
        /// <summary>
        /// 测试项名称
        /// </summary>
        public string name { get; set; }
        /// <summary>
        /// 重测次数
        /// </summary>
        public int testTimes { get; set; }
        /// <summary>
        /// 当前测试次数
        /// </summary>
        public int testTime { get; set; }
        /// <summary>
        /// 最大循环次数
        /// </summary>
        public int loopTimes { get; set; }
        /// <summary>
        /// 当前循环次数
        /// </summary>
        public int loopTime { get; set; }
        /// <summary>
        /// 循环方式 +1.0 / -1.0
        /// </summary>
        public double loopNum { get; set; }
        /// <summary>
        /// 循环仪器标识
        /// </summary>
        public string loopName { get; set; }
        /// <summary>
        /// 失败停止
        /// </summary>
        public bool ngStop { get; set; }
        /// <summary>
        /// 测试指令集合
        /// </summary>
        public List<DeviceOrder> orders { get; set; } = new List<DeviceOrder>();
        /// <summary>
        /// 测试指令仪器标识集合
        /// </summary>
        public List<string> deviceNames => orders.Select(o => o.Device?.name).ToList();
        /// <summary>
        /// 测试指令测试类型集合
        /// </summary>
        public List<string> orderTemps => orders.Select(o => o.Order.temp).ToList();
        /// <summary>
        /// 测试指令测试参数集合
        /// </summary>
        public List<string> orderParameters => orders.Select(o => o.Order.deviceModel).ToList();
        /// <summary>
        /// 测试指令测试字段集合
        /// </summary>
        public List<string> orderMeses => orders.Select(o => o.mes).ToList();
        /// <summary>
        /// 测试指令测试范围集合
        /// </summary>
        public List<string> orderRanges => orders.Select(o => o.Order.range).ToList();

        double time = 0.0;
        /// <summary>
        /// 测试时间
        /// </summary>
        public double Time
        {
            get { return time; }
            set { SetProperty(ref time, value); }
        }
        List<double> times = new List<double>();
        /// <summary>
        /// 测试指令测试时间集合
        /// </summary>
        public List<double> Times
        {
            get { return times; }
            set { SetProperty(ref times, value); }
        }
        TestEnum.TestState state;
        /// <summary>
        /// 测试项状态
        /// </summary>
        public TestEnum.TestState State
        {
            get { return state; }
            set { SetProperty(ref state, value); }
        }
        public List<string> states = new List<string>();
        /// <summary>
        /// 测试指令状态集合
        /// </summary>
        public List<string> States
        {
            get { return states; }
            set { SetProperty(ref states, value); }
        } 
        List<string> resultList = new List<string>();
        /// <summary>
        /// 测试指令结果集合
        /// </summary>
        public List<string> ResultList
        {
            get { return resultList; }
            set { SetProperty(ref resultList, value); }
        }
        /// <summary>
        /// 测试项初始化
        /// </summary>
        public void Init()
        {
            State = TestEnum.TestState.等待;
            Time = 0.0;
            testTime = 0;
            //测试指令初始化
            foreach (var deviceOrder in orders)
            {
                deviceOrder.Init();
            }
            Times = orders.Select(o => o.time).ToList();
            States = orders.Select(o => o.state.ToString()).ToList();
            ResultList = orders.Select(o => o.result.result).ToList();
        }
        /// <summary>
        /// 测试项开始测试
        /// </summary>
        /// <param name="token"></param>
        /// <param name="manualReset"></param>
        public void Start(CancellationToken token = default, ManualResetEvent manualReset = default)
        {
            try
            {
                document.AppendTile2(name, "开始测试");
                State = TestEnum.TestState.测试;
                testTime = 0;
                loopTime = 1;
                loopTimes = 1;
            label2:
                //循环测试指令
                foreach (var order in orders)
                {
                label1:
                    TaskHelper.Wait(token, manualReset);
                    //时间显示
                    DispatcherTimer itemTestTimer = new DispatcherTimer(new TimeSpan(TimeSpan.TicksPerMillisecond * 5), DispatcherPriority.Normal, delegate
                    {
                        Time = orders.Sum(o => o.time);
                        Times = orders.Select(o => o.time).ToList();
                    }, Application.Current.Dispatcher);
                    //测试指令开始测试
                    order.Start(this);
                    //赋值测试指令测试状态
                    States = orders.Select(o => o.state.ToString()).ToList();
                    //赋值测试指令测试结果
                    ResultList = orders.Select(o => o.result.result).ToList();
                    itemTestTimer.Stop();
                    if (order.state != TestEnum.TestState.通过)
                    {
                        //未通过时
                        //是否需要循环测试
                        if (loopTime < loopTimes)
                        {
                            loopTime++;
                            document.AppendTile2(name, "循环" + loopTime);
                            goto label2;
                        }
                        //是否需要复测
                        if (testTimes > testTime)
                        {
                            testTime++;
                            loopTime = 0;
                            document.AppendTile2(name, "复测");
                            goto label1;
                        }
                        if (ngStop)
                        {
                            return;
                        }
                    }
                }
            }
            catch (OperationCanceledException)
            {
                document.AppendTile2(name, "停止测试");
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                //测试完成时更新测试状态
                Times = orders.Select(o => o.time).ToList();
                States = orders.Select(o => o.state.ToString()).ToList();
                ResultList = orders.Select(o => o.result.result).ToList();
                State = States.Count(o => o != TestEnum.TestState.通过.ToString()) == 0 ? TestEnum.TestState.通过 : TestEnum.TestState.失败;
                document.AppendTile2(name, State.ToString());
            }
        }
    }
}
